﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;

using FluentValidation;

using ERPStore.Extensions;
using ERPStore.Web.Routing;

using CloudSoft.Extensions;

namespace ERPStore.Offers.ModelValidators
{
	public class OfferValidator : AbstractValidator<Models.OfferEx>
	{
		private List<string> m_OfferNameDeniedList;

		public OfferValidator(Services.AdminOffersService offerService)
		{
			this.OfferService = offerService;
			m_OfferNameDeniedList = new List<string>()
			{
				"produit"
				, "categorie"
				, "accueil"
				, "panier"
				, "facture"
				, "commande"
				, "devis"
				, "sogenactif"
				, "paypal"
				, "kwixo"
				, "admin"
				, "diagnostic"
				, "newsletter"
				, "offre"
				, "track"
				, "offres"
			};

			RuleFor(m => m.Link).NotEmpty().WithMessage("Vous devez indiquer un lien valide");
			RuleFor(m => m.Name).NotEmpty().WithMessage("Vous devez indiquer un nom");
			RuleFor(m => m.Title).NotEmpty().WithMessage("Vous devez indiquer un titre");
			RuleFor(m => m.Description).NotEmpty().WithMessage("Une offre doit contenir une description");
			RuleFor(m => m.Name).Length(5, 50).WithMessage("Le nom doit contenir entre 5 et 50 caractères");
			RuleFor(m => m.CSSTag).Length(0, 20).WithMessage("Le TagCSS doit contenir entre 0 et 20 caractères");
			RuleFor(m => m.Title).Length(0, 255).WithMessage("Le Titre doit contenir entre 0 et 255 caractères");
			RuleFor(m => m.Link).Length(0, 255).WithMessage("Le lien doit contenir entre 0 et 255 caractères");
			RuleFor(m => m.ProductViewName).Length(0, 50).WithMessage("Le nom de la vue produit doit contenir entre 0 et 50 caractères");
			RuleFor(m => m.ViewName).Length(0, 50).WithMessage("Le nom de la vue doit contenir entre 0 et 50 caractères");

			Custom(offer =>
				{
					if (offer.Link.IsNullOrEmpty())
					{
						return null;
					}

					if (offer.Link.Contains(' '))
					{
						return new FluentValidation.Results.ValidationFailure("Link", "Un lien ne doit pas contenir d'espace");
					}

					try
					{
						new Uri(string.Format("http://www.test.com/{0}", offer.Link.TrimStart('/')));
					}
					catch
					{
						return new FluentValidation.Results.ValidationFailure("Link", "Lien non valide");
					}
					return null;
				});

			Custom(offer =>
				{
					if (offer.Name.IsNullOrTrimmedEmpty())
					{
						return null;
					}
					if (m_OfferNameDeniedList.Contains(offer.Name.ToLower()))
					{
						return new FluentValidation.Results.ValidationFailure("Name", "Ce nom est réservé");
					}

					var existing = OfferService.GetAllOffers().FirstOrDefault(i => i.Name == offer.Name);
					if ((offer.Id == 0 && existing != null) // New Offer
						|| (existing != null && existing.Id != offer.Id)) 
					{
						return new FluentValidation.Results.ValidationFailure("Name", "Ce nom est déjà utilisé");
					}
					return null;
				});

			Custom(offer =>
				{
					var existingLinkList = OfferService.GetAllOffers().Where(i => i.Id != offer.Id).Select(i => i.Link);
					if (existingLinkList.Any(i => i.Equals(offer.Link, StringComparison.InvariantCultureIgnoreCase)))
					{
						return new FluentValidation.Results.ValidationFailure("Link", "Un lien existe déjà avec ce nom");
					}
					return null;
				});

			Custom(offer => // Recherche des liens existants
				{
					string routeName = string.Format("OfferLink.{0}", offer.Name);
					var offerRoute = RouteTable.Routes.GetByName(routeName);

					var existing = OfferService.GetAllOffers().FirstOrDefault(i => i.Name == offer.Name);
					if (offerRoute != null)
					{
						if ((offer.Id == 0 && existing != null)
							|| (existing != null && existing.Id != offer.Id))
						{
							return new FluentValidation.Results.ValidationFailure("Link", "Ce lien (URL) est déjà utilisé");
						}
					}

					return null;
				});

			Custom(offer =>
				{
					if (offer.Description.IsNullOrTrimmedEmpty())
					{
						return null;
					}

					var wordCount = offer.Description.GetWordList().Count;

					if (wordCount < 10)
					{
						return new FluentValidation.Results.ValidationFailure("Description", "Une description doit contenir au moins 10 mots");
					}

					return null;
				});

			Custom(offer =>
				{
					if (!offer.ProductCategoryId.HasValue && !offer.BrandId.HasValue)
					{
						return null;
					}

					if (offer.ProductCategoryId.HasValue)
					{
						var exist = offerService.GetAllOffers().Any(i => i.ProductCategoryId == offer.ProductCategoryId.Value
										&& i.Category == offer.Category
										&& i.Id != offer.Id);
						if (exist)
						{
							return new FluentValidation.Results.ValidationFailure("ProductCategoryId", "Une offre est déjà affectée à cette catégorie");
						}
					}

					if (offer.BrandId.HasValue)
					{
						var exist = offerService.GetAllOffers().Any(i => i.BrandId == offer.BrandId.Value
										&& i.Category == offer.Category
										&& i.Id != offer.Id);

						if (exist)
						{
							return new FluentValidation.Results.ValidationFailure("BrandId", "Une offre est déjà affectée à cette marque");
						}
					}

					return null;
				});
		}

		protected Services.AdminOffersService OfferService { get; private set; }
	}
}
